package com.altekis.kanbankaze.client.ui;

import com.google.gwt.event.shared.GwtEvent;

public class StateChangeEvent extends GwtEvent<StateChangeHandler> {

	public enum State {
		EDITING, VIEWING
	}

	/**
	 * Handler type.
	 */
	private static Type<StateChangeHandler> TYPE;

	/**
	 * Fires a state change event on all registered handlers in the handler
	 * manager. If no such handlers exist, this method will do nothing.
	 * 
	 * @param <T>
	 *            the old value type
	 * @param source
	 *            the source of the handlers
	 * @param value
	 *            the value
	 */
	public static <T> void fire(HasStateChangeHandlers source, State value) {
		if (TYPE != null) {
			StateChangeEvent event = new StateChangeEvent(value);
			source.fireEvent(event);
		}
	}

	/**
	 * Fires state change event if the old value is not equal to the new value.
	 * Use this call rather than making the decision to short circuit yourself
	 * for safe handling of null.
	 * 
	 * @param <T>
	 *            the old value type
	 * @param source
	 *            the source of the handlers
	 * @param oldValue
	 *            the oldValue, may be null
	 * @param newValue
	 *            the newValue, may be null
	 */
	public static <T> void fireIfNotEqual(HasStateChangeHandlers source,
			State oldValue, State newValue) {
		if (shouldFire(source, oldValue, newValue)) {
			StateChangeEvent event = new StateChangeEvent(newValue);
			source.fireEvent(event);
		}
	}

	/**
	 * Gets the type associated with this event.
	 * 
	 * @return returns the handler type
	 */
	public static Type<StateChangeHandler> getType() {
		if (TYPE == null) {
			TYPE = new Type<StateChangeHandler>();
		}
		return TYPE;
	}

	/**
	 * Convenience method to allow subtypes to know when they should fire a
	 * value change event in a null-safe manner.
	 * 
	 * @param <T>
	 *            value type
	 * @param source
	 *            the source
	 * @param oldValue
	 *            the old value
	 * @param newValue
	 *            the new value
	 * @return whether the event should be fired
	 */
	protected static <T> boolean shouldFire(HasStateChangeHandlers source,
			State oldValue, State newValue) {
		return TYPE != null && oldValue != newValue
				&& (oldValue == null || !oldValue.equals(newValue));
	}

	protected final State state;

	public StateChangeEvent(State state) {
		this.state = state;
	}

	@Override
	protected void dispatch(StateChangeHandler handler) {
		handler.onStateChange(this);
	}

	// The instance knows its BeforeSelectionHandler is of type I, but the TYPE
	// field itself does not, so we have to do an unsafe cast here.
	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public final Type<StateChangeHandler> getAssociatedType() {
		return (Type) TYPE;
	}

	/**
	 * @return the state
	 */
	public State getState() {
		return state;
	}

	@Override
	public String toDebugString() {
		return super.toDebugString() + getState();
	}
}
